package com.kkwrite.regimen.provider.util;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

/**
 * Created by Ron on 2018/9/12 13:49.
 *
 * @author Ron
 */
@Component
public class EntityManagerUtil<T> {

    @PersistenceContext
    private EntityManager em;

    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public Tuple singleQuery(Class<T> t, UtilInterface<Selection<Tuple>, T> selection, UtilInterface<Predicate, T> where) {
        Assert.notNull(where, "where must not be null.");
        Assert.notNull(selection, "selection must not be null.");
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Tuple> cq = cb.createTupleQuery();
        Root<T> root = cq.from(t);
        Selection<Tuple> s = selection.get(cb, root);
        if (s == null) {
            throw new IllegalArgumentException("selection must not be null.");
        }
        Predicate p = where.get(cb, root);
        if (p == null) {
            throw new IllegalArgumentException("where must not be null.");
        }
        cq.select(s).where(p);
        return em.createQuery(cq).getSingleResult();
    }

    @FunctionalInterface
    public interface UtilInterface<T, E> {
        /**
         * 获取方法
         * @param cb CriteriaBuilder
         * @param root Root
         * @return T
         */
        T get(CriteriaBuilder cb, Root<E> root);
    }
}
